package org.budo.dubbo.serialize.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;

import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.serialize.ObjectInput;
import com.alibaba.dubbo.common.serialize.ObjectOutput;
import com.alibaba.dubbo.common.serialize.Serialization;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.JSONSerializer;
import com.alibaba.fastjson.serializer.SerializeWriter;
import com.alibaba.fastjson.serializer.SerializerFeature;

import lombok.extern.slf4j.Slf4j;

/**
 * @author lmw
 */
@Slf4j
public class DubboSerializeUtil {
    private static final String UTF_8 = "UTF-8";

    private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";

    /**
     * 将Json反序列化为对象
     */
    public static <T> T deserialize(Serialization serialization, byte[] bodyBytes, Class<T> resultType) {
        try {
            if (serialization.getClass().getSimpleName().equals("FastJsonSerialization")) { // 不同版本的dubbo,包名有变化
                String bodyString_1 = new String(bodyBytes); // 中文乱码特殊处理
                String bodyString_2 = new String(bodyBytes, UTF_8); // 中文乱码特殊处理

                if (log.isTraceEnabled()) {
                    log.trace("#47 bodyString_1=" + bodyString_1 + ", bodyString_2=" + bodyString_2 + ", bodyBytes=" + Arrays.toString(bodyBytes));
                }

                return JSON.parseObject(bodyString_2, resultType);
            }

            // 其他序列化,正常处理
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bodyBytes);
            URL url = null;
            ObjectInput objectInput = serialization.deserialize(url, byteArrayInputStream);

            T resultEntity = objectInput.readObject(resultType);

            if (log.isTraceEnabled()) {
                String bodyString_1 = new String(bodyBytes); // 中文乱码特殊处理
                String bodyString_2 = new String(bodyBytes, UTF_8); // 中文乱码特殊处理
                log.trace("#47 resultEntity=" + resultEntity + ", bodyString_1=" + bodyString_1 + ", bodyString_2=" + bodyString_2 + ", bodyBytes=" + Arrays.toString(bodyBytes));
            }

            return resultEntity;
        } catch (Throwable e) {
            throw new RuntimeException("#44 deserialize error, serialization=" + serialization //
                    + ", headerResultType=" + resultType, e);
        }
    }

    /**
     * @see com.alibaba.dubbo.common.serialize.support.json.FastJsonObjectOutput#writeObject(Object)
     */
    public static byte[] serializeResultValue(Serialization serialization, Object resultValue, Boolean useDateFormat) {
        try {
            if (serialization.getClass().getSimpleName().equals("FastJsonSerialization")) { // 不同版本的dubbo,包名有变化
                SerializeWriter serializeWriter = new SerializeWriter();
                JSONSerializer jsonSerializer = new JSONSerializer(serializeWriter);

                jsonSerializer.config(SerializerFeature.WriteEnumUsingToString, true);

                if (null != useDateFormat && useDateFormat) {
                    jsonSerializer.config(SerializerFeature.WriteDateUseDateFormat, true);
                    jsonSerializer.setDateFormat(DATE_FORMAT);
                }

                jsonSerializer.write(resultValue);

                byte[] bytes = serializeWriter.toBytes(UTF_8);
                serializeWriter.close(); // for reuse SerializeWriter buf

                if (log.isTraceEnabled()) {
                    log.trace("#127 str_1=" + new String(bytes) + ", str_2=" + new String(bytes, UTF_8) + ", resultValue=" + resultValue + ", bytes=" + Arrays.toString(bytes));
                }

                return bytes;
            }

            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            ObjectOutput objectOutput = serialization.serialize(null, byteArrayOutputStream);
            objectOutput.writeObject(resultValue);
            byte[] bytes = byteArrayOutputStream.toByteArray();

            if (log.isTraceEnabled()) {
                log.trace("#139 str_1=" + new String(bytes) + ", str_2=" + new String(bytes, UTF_8) + ", resultValue=" + resultValue + ", bytes=" + Arrays.toString(bytes));
            }

            return bytes;
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 将对象序列化为Json
     */
    public static String serialize(Invocation invocation, Serialization serialization) throws IOException {
        URL url = invocation.getInvoker().getUrl();
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream);

        objectOutput.writeObject(invocation);
        byte[] bytes = byteArrayOutputStream.toByteArray();
        String str = new String(bytes, UTF_8);

        if (log.isTraceEnabled()) {
            log.trace("#74 str=" + str + ", bytes=" + Arrays.toString(bytes) + ", invocation=" + invocation + ", serialization=" + serialization);
        }

        return str;
    }
}